<template>
  <section>
    <a-form-model>
      <a-form-model-item label="选择导出的字段">
        <a-checkbox :indeterminate="indeterminate" v-model="checkAll">
          全选<span style="color: red"
            >（导出后如需再导入请选择全字段导出）</span
          >
        </a-checkbox>

        <!-- 支持排序 -->
        <template v-if="isSupportSort">
          <a-row>
            <a-col span="10">
              <section>
                <label for="">可选表头字段<span style="color: red">(支持鼠标按住拖拽或者选中一项添加到右侧)</span></label>
              </section>
              <section>
                <a-row>
                  <draggable
                    class="select-container"
                    v-model="currentSortFields"
                    group="execl"
                    tag="ul"
                    v-bind="dragOptions"
                    @drop.native="handlerDragMove"
                  >
                    <transition-group type="transition" >
                      <li
                        @click="handlerSortSelected(item, index)"
                        :span="24 / column"
                        v-for="(item, index) in currentSortFields"
                        :key="item.value"
                        ref="sort"
                        class="select"
                        :class="{'selected': item.currentIsSelected}"
                      >
                        {{ item.label }}
                      </li>
                      <div class="empty" v-show="!currentSortFields.length" key="empty">暂无字段</div>
                    </transition-group>
                  </draggable>
                </a-row>
              </section>
            </a-col>

            <a-col span="2" offset="1">
              <div class="button-group">
                <a-button :disabled="currentSortSelectedIndex === -1" @click="handlerAddSelected">添加 -></a-button>
                <a-button :disabled="currentSortedSelectedIndex === -1" @click="handlerDelSelected"><- 删除</a-button>
                <a-button @click="initSorted" class="init">还原默认值</a-button>
                <a-button :disabled="!isMove" @click="handlerMoveToTop(true)">上移∧</a-button>
                <a-button :disabled="!isMove" @click="handlerMoveToBottom(true)">下移∨</a-button>
              </div>
            </a-col>

            <a-col span="10" offset="1">
              <section>
                <label for=""
                  >已选表头字段
                  <span style="color: red">(支持鼠标按住拖拽排序、灰色字段是必须导出的字段)</span>
                </label>
              </section>
              <section>
                <a-row>
                  <draggable
                    class="select-container"
                    v-model="currentSortedFields"
                    group="execl"
                    tag="ul"
                    v-bind="dragOptions"
                    @drop.native="handlerDragMove"
                  >
                    <transition-group type="transition">
                      <li
                        :span="24 / column"
                        @click="handlerSortedSelected(item, index)"
                        v-for="(item, index) in currentSortedFields"
                        :key="item.value"
                        class="select"
                        ref="sorted"
                        :class="{'ignore-elements': item.selected, 'selected': item.currentIsSelected}"
                      >
                        {{ index + 1 }}）{{ item.label }}
                      </li>
                      <div class="empty" v-show="!currentSortedFields.length" key="empty">暂无字段</div>
                    </transition-group>
                  </draggable>
                </a-row>
              </section>
            </a-col>
          </a-row>
        </template>

        <!-- 不支持排序 -->
        <template v-else>
          <a-checkbox-group v-model="currentSelected">
            <a-row>
              <a-col
                :span="24 / column"
                v-for="item in fields"
                :key="item.value"
              >
                <a-checkbox :value="item.value" :disabled="item.disabled">{{
                  item.label
                }}</a-checkbox>
              </a-col>
            </a-row>
          </a-checkbox-group>
        </template>
      </a-form-model-item>
      <a-form-model-item label="选择导出的格式">
        <a-radio-group v-model="currentType">
          <!-- <a-radio :value="0">按当前行政区下级行政区分组导出</a-radio>
          <a-radio :value="1">按当前行政区导出</a-radio> -->
          <a-radio :value="0">按选定行政区的下一级行政区名称分组导出</a-radio>
          <a-radio :value="1">按选定行政区导出</a-radio>
          <!-- <a-radio :value="2">按选定行政区的下一级行政区分组导出多个电子表文件</a-radio> -->
        </a-radio-group>
      </a-form-model-item>
    </a-form-model>
  </section>
</template>

<script lang="ts">
import { Mixins, Component, Vue, Prop, Watch } from 'vue-property-decorator'
import CustomForm from '@/components/src/Form'
import { userModule } from '@/store/modules/user'
import draggable from 'vuedraggable'

type IField = ITable.IDictOption & { selected: boolean, currentIsSelected?: boolean }

@Component({
  components: {
    CustomForm,
    draggable,
  },
})
export default class SelectExportField extends Vue {
  @Prop({
    type: Array,
  })
  public fields!: (ITable.IDictOption & { selected: boolean })[]

  @Prop({
    type: Boolean,
    default: false,
  })
  public isSupportSort!: boolean

  get isLarge() {
    return userModule.isLarge
  }

  public currentSelected: (string | number)[] = []
  public currentType = 0

  public currentSortedFields: IField[] =
    []
  public currentSortFields: IField[] = []

  public dragOptions = {
    animation: 200,
    ghostClass: "ghost",
    filter: ".ignore-elements",
    emptyInsertThreshold: 20,
    onMove: function() {
      console.log(1)
    }
  };

  get column() {
    return this.isSupportSort ? 1 : 4
  }

  set checkAll(value: boolean) {
    if (this.isSupportSort) {
      if (value) {
        this.currentSortedFields = this.fields
        this.currentSortFields = []
      } else {
        this.initSorted()
      }
    } else {
      // @ts-ignore
      this.currentSelected = value
        ? this.fields.map((options) => options.value)
        : this.fields
            .filter((field) => field.selected)
            .map((options) => options.value)
    }
  }

  get checkAll() {
    return this.isSupportSort
      ? this.currentSortedFields.length === this.fields.length
      : this.currentSelected.length === this.fields.length
  }

  get indeterminate() {
    return this.isSupportSort
      ? Boolean(this.currentSortedFields.length) &&
        this.currentSortedFields.length !== this.fields.length
      : Boolean(this.currentSelected.length) &&
          this.currentSelected.length !== this.fields.length
  }

  public initSorted() {
    this.currentSortedFields = this.fields.filter((field) => field.selected).map(item => ({...item}))
    this.currentSortFields = this.fields.filter((field) => !field.selected).map(item => ({...item}))
  }

  public handlerDragMove(evt: Event, originalEvent: unknown) {
    evt.stopPropagation()
    evt.preventDefault()
    this.handlerSortSelected(null, -1)
    this.handlerSortedSelected(null, -1)
  }

  get isMove () {
    return this.currentSortSelectedIndex !== -1 || this.currentSortedSelectedIndex !== -1
  }

  public currentSortSelectedIndex = -1
  public handlerSortSelected(item: IField | null, index: number) {
    this.currentSortFields.forEach(_ => {
      // @ts-ignore
      this.$set(_, 'currentIsSelected', false)
    })
    // 重置
    if (item) {
      item.currentIsSelected = !item.currentIsSelected
      this.handlerSortedSelected(null, -1)
    }
    this.currentSortSelectedIndex = index
  }

  public handlerAddSelected() {
    // let leftIndex = this.currentSortSelectedIndex
    // this.handlerAddSelected()
    
    if (this.currentSortSelectedIndex !== -1) {
      const item = this.currentSortFields[this.currentSortSelectedIndex];
      this.currentSortedFields.push({
        ...item,
        currentIsSelected: false
      })
      this.currentSortFields.splice(this.currentSortSelectedIndex, 1)
      if (this.currentSortSelectedIndex === this.currentSortFields.length) {
        this.currentSortSelectedIndex--;
      }
      this.handlerIndexUpdate('left', this.currentSortSelectedIndex)
      // this.currentSortSelectedIndex = -1;
    }
  }

  public currentSortedSelectedIndex = -1
  public handlerSortedSelected(item: IField | null, index: number) {
    if (!this.currentSortedFields.length) return
    this.currentSortedFields.forEach(_ => {
      // @ts-ignore
      this.$set(_, 'currentIsSelected', false)
    })
    // 重置
    if (item) {
      item.currentIsSelected = !item.currentIsSelected
      this.handlerSortSelected(null, -1)
    }
    this.currentSortedSelectedIndex = index
  }

  public handlerDelSelected() {
    if (this.currentSortedSelectedIndex !== -1) {
      const item = this.currentSortedFields[this.currentSortedSelectedIndex];
      // 标记必须导出的不能移除
      if (item.selected) {
        this.$message.error('该字段必须导出')
        return
      }
      this.currentSortFields.push({
        ...item,
        currentIsSelected: false
      })
      this.currentSortedFields.splice(this.currentSortedSelectedIndex, 1)
      // 已选择空
      if (this.currentSortedSelectedIndex === this.currentSortedFields.length) {
        this.currentSortedSelectedIndex--;
      }
      this.handlerIndexUpdate('right', this.currentSortedSelectedIndex)
    }
  }

  public handlerMoveToTop(isExchange = false) {
    if (this.currentSortSelectedIndex > 0) {
      this.currentSortSelectedIndex--;
      if (isExchange) {
        // 交换两个元素的位置
        this.SwapArrayItem(this.currentSortFields, this.currentSortSelectedIndex + 1, this.currentSortSelectedIndex)
      }
      this.handlerIndexUpdate('left', this.currentSortSelectedIndex)
      this.scrollToView('left', this.currentSortSelectedIndex)
    } else if (this.currentSortedSelectedIndex > 0){
      this.currentSortedSelectedIndex--;
      if (isExchange) {
        // 交换两个元素的位置
        this.SwapArrayItem(this.currentSortedFields, this.currentSortedSelectedIndex + 1, this.currentSortedSelectedIndex)
      }
      this.handlerIndexUpdate('right', this.currentSortedSelectedIndex)
      this.scrollToView('right', this.currentSortedSelectedIndex)
    }
  }

  public handlerMoveToBottom(isExchange = false) {
    if (this.currentSortedSelectedIndex !== -1){
      if (this.currentSortedSelectedIndex < this.currentSortedFields.length - 1) {
        this.currentSortedSelectedIndex++;
        if (isExchange) {
          // 交换两个元素的位置
          this.SwapArrayItem(this.currentSortedFields, this.currentSortedSelectedIndex - 1, this.currentSortedSelectedIndex)
        }
        this.handlerIndexUpdate('right', this.currentSortedSelectedIndex)
        this.scrollToView('right', this.currentSortedSelectedIndex)
      }
    } else {
      if (this.currentSortSelectedIndex < this.currentSortFields.length - 1) {
        this.currentSortSelectedIndex++;
        if (isExchange) {
          // 交换两个元素的位置
          this.SwapArrayItem(this.currentSortFields, this.currentSortSelectedIndex - 1, this.currentSortSelectedIndex)
        }
        this.handlerIndexUpdate('left', this.currentSortSelectedIndex)
        this.scrollToView('left', this.currentSortSelectedIndex)
      }
    }
  }

  public handlerIndexUpdate(mode: 'left' | 'right', index: number) {
    mode === 'left'
      ? this.handlerSortSelected(this.currentSortFields[index], index)
      : this.handlerSortedSelected(this.currentSortedFields[index], index)
  }

  public SwapArrayItem(arr: IField[], sourceIndex: number, targetIndex: number) {
    if (sourceIndex < 0 || sourceIndex >= arr.length || targetIndex < 0 || targetIndex >= arr.length) return
    arr[sourceIndex] = arr.splice(targetIndex, 1, arr[sourceIndex])[0];
    return arr;
  }

  public scrollToView(mode: 'left' | 'right', index: number) {
    (<HTMLElement[]>this.$refs[mode === 'left' ? 'sort' : 'sorted'])[index].scrollIntoView({
      behavior: 'smooth',
      block: 'center'
    })
  }

  public mounted() {
    this.currentSelected = this.fields
      .filter((field) => field.selected)
      .map((options) => options.value)
    if (this.isSupportSort) this.initSorted()

    const handler = (e: KeyboardEvent) => {
      e.stopPropagation()
      e.preventDefault()
      switch(e.code) {
        case 'ArrowLeft':
          this.handlerDelSelected()
          break;
        case 'ArrowRight':
          this.handlerAddSelected()
          break;
        case 'ArrowUp':
          this.handlerMoveToTop(e.shiftKey)
          break;
        case 'ArrowDown':
          this.handlerMoveToBottom(e.shiftKey)
          break;
        case 'Tab':
          if (this.currentSortSelectedIndex !== -1) {
            // 右侧没有字段时
            if (!this.currentSortedFields.length) {
              // this.$message.error('右侧无任何字段，不能切换！')
              return
            }
            this.currentSortedSelectedIndex = 0;
            this.currentSortSelectedIndex = -1;
            this.handlerIndexUpdate('right', this.currentSortedSelectedIndex)
          } else {
            // 左侧没有字段时
            if (!this.currentSortFields.length) {
              // this.$message.error('左侧无任何字段，不能切换！')
              return
            }
            this.currentSortedSelectedIndex = -1
            this.currentSortSelectedIndex = 0;
            this.handlerIndexUpdate('left', this.currentSortSelectedIndex)
          }
          break;
      }
    }

    document.addEventListener('keydown', handler)
    this.$once('hook:beforeDestroy', () => {
      document.removeEventListener('keydown', handler)
    })
  }
}
</script>

<style scoped lang="less">
.title {
  line-height: 30px;
  text-indent: 8px;
  span:nth-child(2) {
    margin: 0 10px;
  }
}
.select-container {
  border: 1px solid #ddd;
  padding: 10px;
  border-radius: 5px;
  height: 400px;
  overflow-y: scroll;
  margin-bottom: 20px;
}
.select {
  height: 32px;
  line-height: 32px;
  border: 1px solid #ddd;
  cursor: pointer;
  text-indent: 1em;
  border-radius: 2px;
  margin-bottom: 2px;
}

.flip-list-move {
  transition: transform 0.5s;
}
.empty {
  line-height: 100px;
  color: #999;
  text-align: center;
  width: 100%;
  height: 400px;
  position: relative;
  z-index: 1;
}
.ignore-elements {
  background-color: #eee;
  cursor: not-allowed;
}
.button-group {
  width: 100%;
  height: 400px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  button {
    margin-top: 10px;
    width: 100px;
  }
  .init {
    margin: 40px 0;
  }
}
.selected {
  background-color: #e1102d;
  border: 1px solid #e1102d;
  color: #fff;
}
</style>
